namespace Sage.Http.Handlers
{
    /// <summary>
    /// 超时处理器，为HTTP请求设置超时时间
    /// </summary>
    /// <remarks>
    /// 初始化超时处理器
    /// </remarks>
    /// <param name="timeout">超时时间</param>
    public class TimeoutHandler(TimeSpan timeout) : DelegatingHandler
    {
        private readonly TimeSpan _timeout = timeout > TimeSpan.Zero ? timeout : throw new ArgumentOutOfRangeException(nameof(timeout), "超时时间必须大于零");

        /// <summary>
        /// 发送HTTP请求并应用超时控制
        /// </summary>
        /// <param name="request">HTTP请求</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>HTTP响应</returns>
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CancellationTokenSource? timeoutCts = null;
            CancellationTokenSource? linkedCts = null;
            var effectiveTimeout = _timeout;

            try
            {
                // 读取请求级超时（如果存在）
                if (request.Options.TryGetValue(new HttpRequestOptionsKey<TimeSpan>("RequestTimeout"), out var requestTimeout)
                    && requestTimeout > TimeSpan.Zero)
                {
                    effectiveTimeout = requestTimeout;
                }

                // 创建超时取消令牌源
                timeoutCts = new CancellationTokenSource(effectiveTimeout);

                // 将超时令牌与原始令牌组合
                linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

                // 使用组合的取消令牌发送请求
                return await base.SendAsync(request, linkedCts.Token);
            }
            catch (OperationCanceledException ex) when (timeoutCts?.Token.IsCancellationRequested == true && !cancellationToken.IsCancellationRequested)
            {
                // 超时导致的取消
                throw new TimeoutException($"请求在 {effectiveTimeout.TotalSeconds} 秒后超时", ex);
            }
            catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
            {
                // 用户主动取消，重新抛出原始异常
                throw;
            }
            finally
            {
                // 确保资源被正确释放
                linkedCts?.Dispose();
                timeoutCts?.Dispose();
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否正在释放托管资源</param>
        protected override void Dispose(bool disposing)
        {
            // TimeoutHandler 本身不持有需要释放的资源
            // CancellationTokenSource 在 SendAsync 方法中已经正确释放
            base.Dispose(disposing);
        }
    }
}
